﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Drawing;
using System.Numerics;
using Vux.Helper.Numeric;

namespace Vux.Imaging
{
    public class PaletteHiding
    {
        private string m_str_image_url;
        private Bitmap m_bmp_gif;
        private BigUInt calc;

        public string GifUrl
        {
            get { return m_str_image_url; }
            set { m_str_image_url = value; }
        }

        public PaletteHiding()
        {
            m_ht_initial_palette = new Hashtable(256);
            calc = BigUInt.Create(256);
        }

        public PaletteHiding(string ip_str_gif)
            : this()
        {
            m_str_image_url = ip_str_gif;
            m_bmp_gif = new Bitmap(ip_str_gif);
            GenStandarPalette();
            var vunb = Encoding.UTF8.GetBytes("Vũ");
            var b = new byte[] { 15 }; // dữ liệu test;
            var a = new byte[] { 2, 1, 3, 0 };
            var enc = Encode(b);
            var dec = Decode(enc);

            enc = Encode(vunb);
            dec = Decode(enc);
        }

        /// <summary>
        /// Mã tin mật
        /// </summary>
        /// <param name="ip_confidental_information">Tin mật dưới dạng mảng byte</param>
        /// <returns>Cấu hình mới của Pallete so với cấu hình chuẩn</returns>
        public byte[] Encode(byte[] ip_confidental_information)
        {
            #region Version 1
            //// Tin mật chính là thứ tự cấu hình của palette so với cấu hình chuẩn
            //var stt = BitConverter.ToDouble(ip_confidental_information, 0);
            //var backup_standard = new List<Color>(m_color_palette);
            //var new_cau_hinh = new List<Color>();
            //var index = m_color_palette.Count;
            //while (index > 0)
            //{
            //    // số vòng quay.
            //    var turns = (int)(stt / Factorial(index));
            //    new_cau_hinh.Add(backup_standard[turns]);
            //    backup_standard.RemoveAt(turns);
            //    index = backup_standard.Count;
            //}
            //return new_cau_hinh;
            #endregion

            #region Version 2

            if (ip_confidental_information.Length > 172)
            {
                throw new Exception("Du lieu mat qua lon, nho hon 172 bytes");
            }

            // Tin mật chính là thứ tự cấu hình của palette so với cấu hình chuẩn
            //var calc = Vux.Helper.Numeric.BigUInt.Create(256);

            var stt = ip_confidental_information.Clone() as byte[];
            var cau_hinh_chuan = GenStandardConfiguration(m_color_palette.Count);
            var cau_hinh_moi = new byte[cau_hinh_chuan.Count];

            #region Version 2

            var remain = cau_hinh_chuan.Count - 1;
            var i = 0; // coi danh là cấu hình chuẩn, theo thứ tự duyệt từng vị trí từ chỉ số 0
            while (remain > 0) // remain : Count -> 1
            {
                var fac = ByteHelper.GetFactorial(remain);
                var re = calc.Chia(stt, fac, out stt);

                var index = re.ToIntValue(0);

                var pop = cau_hinh_chuan[index];
                cau_hinh_chuan.RemoveAt(index);

                cau_hinh_moi[i] = pop; // mod 256, số ph.tử của tập hợp 256 màu -> explicit luôn sang byte
                remain--;
                i++;
            }
            cau_hinh_moi[i] = cau_hinh_chuan[0];

            #endregion

            #region Version 3
            // Thực hiện tăng vị trí tương đối của bộ cấu hình từ trái sang phải
            //var offset = 0;
            //while (stt.IsZero() == false)
            //{

            //}

            #endregion

            return cau_hinh_moi;
            #endregion
        }
        /// <summary>
        /// Giải mã tin mật
        /// </summary>
        /// <param name="configuration_palette">Cấu hình hiện tại của Palette</param>
        /// <returns>Tin mật</returns>
        private byte[] Decode(byte[] configuration_palette)
        {
            var plen = configuration_palette.Length;
            var remain = plen - 1;
            if (remain > 0)
            {
                var sort = new byte[plen];
                Array.Copy(configuration_palette, sort, plen);
                Array.Sort(sort);

                var index = Array.IndexOf(sort, configuration_palette[0]);
                var fac = ByteHelper.GetFactorial(remain);
                var step_value = fac.Mutiply(index);

                var next = new byte[remain];
                Array.Copy(configuration_palette, 1, next, 0, remain);

                return calc.Cong(step_value, Decode(next)).Trim();
            }
            return new byte[1] { 0 };
        }

        /// <summary>
        /// Sắp xếp lại 
        /// </summary>
        private void ArrangePalette()
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Lưu trữ thông tin của bảng màu ban đầu (chưa thay đổi gì cả)
        /// Màu thứ i ở trong data tương ứng màu nào <index, color>
        /// </summary>
        private Hashtable m_ht_initial_palette;
        /// <summary>
        /// Cấu hình hiện tại của palette màu
        /// </summary>
        private List<int> m_list_configuration;
        /// <summary>
        /// Lưu trữ thông tin bảng màu,
        /// Sắp xếp thứ tự từ bé đến lớn (cấu hình chuẩn)
        /// </summary>
        private List<Color> m_color_palette;

        private List<byte> GenStandardConfiguration(int elements)
        {
            var list = new List<byte>();
            for (int i = 0; i < elements; i++)
            {
                list.Add((byte)i);
            }
            return list;
        }

        private void GenStandarPalette()
        {
            //for (int i = 0; i < m_bmp_gif.Palette.Entries.Length; i++)
            //{
            //    // Chỉ số i tương ứng màu Entries[i].
            //    m_ht_initial_palette[i] = m_bmp_gif.Palette.Entries[i];
            //}
            // Qui tắc cập nhật như sau:
            // 1. Xác định cấu hình chuẩn của palette bằng cách sắp xếp lại, từ đó tìm cấu hình tương ứng dữ liệu mật
            // 2. Lưu lại cấu hình hiện tại của palette tương ứng là các chỉ mục của nó
            // 3. Thay đổi cấu hình palette cũ bằng cấu hình mật vừa tìm được ở bước (2)
            // 4. Cập nhật lại dữ liệu vùng data bằng các bước tiếp sau
            // 5. Từ vùng dữ liệu cũ, lấy được chỉ số màu trong bảng màu (tất nhiên đây là thông tin ban đầu)
            // 6. 
            //var v_bmp_data = m_bmp_gif.LockBits(new Rectangle(0,0, m_bmp_gif.Width, m_bmp_gif.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
            //m_bmp_gif.UnlockBits(v_bmp_data);

            //1. Xây dựng cấu hình chuẩn
            m_color_palette = new List<Color>(m_bmp_gif.Palette.Entries);
            m_color_palette.Sort(new ColorComparer());
        }

        private class ColorComparer : IComparer<Color>
        {
            #region IComparer<Color> Members

            public int Compare(Color x, Color y)
            {
                var c1 = (Color)x;
                var c2 = (Color)y;
                if (c1.B != c2.B)
                {
                    return c1.B.CompareTo(c2.B);
                }
                else if (c1.G != c2.G)
                {
                    return c1.G.CompareTo(c2.G);
                }
                else if (c1.R != c2.R)
                {
                    return c1.R.CompareTo(c2.R);
                }
                return 0;
            }

            #endregion
        }
    }
}
